package com.xl.rentkeeper.business;

import android.text.TextUtils;

import com.google.gson.Gson;
import com.xl.fuse.protos.msg.GetMsgAck;
import com.xl.fuse.protos.msg.GetMsgReq;
import com.xl.fuse.protos.msg.GetMsgResp;
import com.xl.fuse.protos.msg.Msg;
import com.xl.fuse.protos.msg.MsgBody;
import com.xl.fuse.protos.msg.MsgHead;
import com.xl.fuse.protos.msg.MsgPush;
import com.xl.fuse.protos.msg.MsgSyncFlag;
import com.xl.fuse.protos.msg.MsgType;
import com.xl.fuse.protos.msg.SendMsg;
import com.xl.fuse.protos.packet.Packet;
import com.xl.rentkeeper.App;
import com.xl.rentkeeper.log.QLog;
import com.xl.rentkeeper.mgr.ThreadManager;
import com.xl.rentkeeper.mgr.UiObserverManager;
import com.xl.rentkeeper.msg.Message;
import com.xl.rentkeeper.net.IPushCallback;
import com.xl.rentkeeper.net.NetEngine;
import com.xl.rentkeeper.net.Request;
import com.xl.rentkeeper.util.ErrString;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Created by zwc on 2015/7/24.
 */
public class MsgLogic extends BaseLogic implements IPushCallback {
    private boolean isPulling = false;
    public static MsgLogic getInstance() {
        return (MsgLogic) SingletonRegistry.getInstance(MsgLogic.class);
    }
    private static final String Key_Seq = "key_seq";

    @Override
    public void onPush(Packet packet) {
        MsgPush push = getResp(packet, MsgPush.class);
        if (push != null) {
            QLog.d(this, "onPush " + push.toString());
            if (push.svrSeq > msgConfig.seq) {
                pullMsg();
            }
        }
        pullMsg();
    }

    @Override
    public void onConnConnect() {
        QLog.d(this, "onConnConnect");
        if (UserLogic.getInstance().isLogin()) {
            pullMsg();
        }
    }

    @Override
    public void onConnDisconnect() {
        QLog.d(this, "onConnDisconnect");
    }

    static class MsgConfig {
        public long seq;
    }
    MsgConfig msgConfig;

    public List<Message> getMessages() {
        lock.lock();
        List<Message> msgs = new ArrayList<>(messages);
        lock.unlock();
        return msgs;
    }
    private List<Message> messages = new LinkedList<>();

    private MsgLogic() {
        msgConfig = new MsgConfig();
        String p = getUserSp().getString(Key_Seq, "");
        if (!TextUtils.isEmpty(p)) {
            try {
                MsgConfig configs = new Gson().fromJson(p,MsgConfig.class);
                this.msgConfig = configs;
            } catch (Exception e) {
                e.printStackTrace();
                msgConfig = new MsgConfig();
            }
        }
        loadFromDb();
        NetEngine.getInstance().setPushCallback(this);
    }
    private void loadFromDb() {
        ThreadManager.getInstance().runOnWorkerThread(new Runnable() {
            @Override
            public void run() {
                List<Message> msgs = getDb().find(null, Message.class, null, null, null, "msg_time desc", "100");
                lock.lock();
                messages.clear();
                messages.addAll(msgs);
                lock.unlock();
                UiObserverManager.getInstance().dispatchEvent(CMD_MSG_PULL, true, null,null);
            }
        }, 0);
    }

    public void pullMsg() {
        if(isPulling) {
            QLog.d(this,"pullMsg isPulling");
            return;
        }
        if (UserLogic.getInstance().getUid() <= 0) {
            QLog.d(this,"pullMsg no login");
            return;
        }
        isPulling = true;
        GetMsgReq getMsgReq = new GetMsgReq.Builder().cliSeq(msgConfig.seq).syncFlag(MsgSyncFlag.SYNC_BEGIN).build();
        sendReq(CMD_MSG_PULL, getMsgReq, null);
    }


    private void sendMsg(MsgHead head,MsgBody body){
        Msg msg = new Msg.Builder().msgHead(head).msgBody(body).build();
        SendMsg sendMsgReq = new SendMsg.Builder().msg(msg).build();
        sendReq("", sendMsgReq, null);
    }

    @Override
    public void onResp(Request req, Packet resp) {
        super.onResp(req, resp);
        Packet packet = req.packet;
        String cmd = packet.cmd;
        if (CMD_MSG_PULL.equals(cmd)) {
            onPullResp(req,resp);
        } else if (CMD_MSG_PULLACK.equals(cmd)) {
            QLog.d(this,"pull ack resp ret:"+resp.ret);
        } else if (CMD_MSG_SEND.equals(cmd)) {
            QLog.d("msg","resp.ret:"+resp.ret);
            if(resp.ret != 0){
                App.showToast(ErrString.getErrTip(resp.ret));
            }
            UiObserverManager.getInstance().dispatchEvent(cmd, resp.ret == 0,resp.error, null);
        }
    }


    private void onPullResp(Request req, Packet resp) {
        Packet packet = req.packet;
        String cmd = packet.cmd;
        isPulling = false;
        if (resp.ret == 0) {
            GetMsgResp getMsgResp = getResp(resp,GetMsgResp.class);
            if (getMsgResp != null) {
                QLog.d(this,"getMsgResp:"+getMsgResp.toString());
                if (getMsgResp.srvSeq > msgConfig.seq) {
                    lock.lock();
                    int i = 0;
                    List<Message> toSave = new ArrayList<>(getMsgResp.msg.size());
                    List<Msg> toOrderPushList = new ArrayList<>();
                    Map<Long,Msg> msgMap = new HashMap<>();
                    for (Msg msg : getMsgResp.msg) {
                        Message message = new Message();
                        message.fromUin = msg.msgHead.fromUin;
                        message.toUin = msg.msgHead.toUin;
                        message.msg = msg;
                        message.seq = msg.msgHead.msgSeq;
                        message.msgTime = msg.msgHead.msgTime;
                        message.receivingTime = System.currentTimeMillis();
                        message.data = msg.toByteArray();
                        if (message.seq < msgConfig.seq) {
                            continue;
                        }
                        if (msgMap.containsKey(msg.msgHead.msgSeq)) {
                            continue;
                        }
                        if(msg.msgHead.msgType == MsgType.NEW_VIEW_ORDER.getValue() || msg.msgHead.msgType == 2 || msg.msgHead.msgType == 3){
                            toOrderPushList.add(msg);
                        }
                        msgMap.put(msg.msgHead.msgSeq,msg);
                        messages.add(i, message);
                        toSave.add(message);
                        i++;
                    }
                    lock.unlock();
                    // save msg to db
                    getDb().saveInTx(null, toSave);
                    msgConfig.seq = getMsgResp.srvSeq;
                    saveConfig();
                    OrderLogic.getInstance().onPushOrder(toOrderPushList);
                }
                GetMsgAck ack = new GetMsgAck.Builder().cliSeq(msgConfig.seq).build();
                sendReq(CMD_MSG_PULLACK,ack,null);
                UiObserverManager.getInstance().dispatchEvent(cmd, resp.ret == 0,resp.error, null);
            }
        } else {
            UiObserverManager.getInstance().dispatchEvent(cmd, resp.ret == 0,resp.error, null);
        }
    }

    private void saveConfig() {
        getUserSp().edit().putString(Key_Seq,new Gson().toJson(msgConfig)).commit();
    }

    public void onNetStateChange(Message msg){
        lock.lock();
        messages.add(0, msg);
        List<Message> toSave = new ArrayList<>();
        toSave.add(msg);
        getDb().saveInTx(null, toSave);
        lock.unlock();
        UiObserverManager.getInstance().dispatchEvent(CMD_MSG_PULL, true,null, null);
    }
}
